﻿/********************************************************
 * ADO.NET 2.0 Data Provider for EffiProz Version 3.X
 * Written by Robert Simpson (robert@blackcastlesoft.com)
 * 
 * Released to the public domain, use at your own risk!
 ********************************************************/

using System;
using Microsoft.VisualStudio.Data;
using System.Windows.Forms.Design;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.OLE.Interop;
using System.Data.Common;
using System.Globalization;
using EffiProz.Designer.Editors;


namespace EffiProz.Designer
{

    enum cmdid
    {
        CreateTable = 0x3520,
        CreateView = 0x3521,
        Alter = 0x3003,
        Refresh = 0x3004,
        Delete = 17,
        Checkpoint = 262,
        Rekey = 263,
        Triggers = 264,
    }

    internal sealed class EfzCommandHandler : DataViewCommandHandler
    {
        internal static readonly Guid guidDataCmdSet = new Guid("501822E1-B5AF-11d0-B4DC-00A0C91506EF");
        internal static readonly Guid guidEffiProzCmdSet = new Guid("15312D5C-AE70-4220-BFDD-617A8EB8EDB8");
        internal static readonly Guid guidIFCmdId = new Guid("{74d21311-2aee-11d1-8bfb-00a0c90f26f7}");
        internal static readonly Guid guidDavinci = new Guid("{732abe75-cd80-11d0-a2db-00aa00a3efff}");
        internal static readonly Guid guidDavinciGrp = new Guid("{732abe74-cd80-11d0-a2db-00aa00a3efff}");
        internal static readonly Guid guidQueryGroup = new Guid("5efc7975-14bc-11cf-9b2b-00aa00573819");
        internal static Guid guidTableDesignContext = new Guid("4194fee5-6777-419f-a5fc-47a536df1bdb");
        internal static Guid guidViewDesignContext = new Guid("b968e165-98e0-41f0-8fbe-a8ed1d246a90");

        public EfzCommandHandler()
        {
        }

        public override OleCommandStatus GetCommandStatus(int[] itemIds, OleCommand command, OleCommandTextType textType, OleCommandStatus status)
        {
            if (command.GroupGuid == guidEffiProzCmdSet)
            {
                switch ((cmdid)command.CommandId)
                {
                    case cmdid.CreateTable:
                    case cmdid.Checkpoint:
                    case cmdid.Rekey:
                        status.Supported = true;
                        status.Visible = true;
                        status.Enabled = true;
                        return status;
                }
            }
            else if (command.GroupGuid == VSConstants.GUID_VSStandardCommandSet97)
            {
                switch ((VSConstants.VSStd97CmdID)command.CommandId)
                {
                    case VSConstants.VSStd97CmdID.Delete:
                        status.Supported = true;
                        status.Visible = true;
                        status.Enabled = (SystemTableSelected == false && SystemIndexSelected == false);
                        return status;
                }
            }
            else if (command.GroupGuid == guidDataCmdSet)
            {
                switch ((cmdid)command.CommandId)
                {
                    case cmdid.Alter:
                        status.Supported = true;
                        status.Visible = true;
                        status.Enabled = (SystemTableSelected == false && SystemIndexSelected == false);
                        return status;
                    case cmdid.CreateTable:
                    case cmdid.CreateView:
                        status.Supported = true;
                        status.Visible = true;
                        status.Enabled = true;
                        return status;
                }
            }
            base.GetCommandStatus(itemIds, command, textType, status);

            return status;
        }

        private bool SystemTableSelected
        {
            get
            {
                int[] items = DataViewHierarchyAccessor.GetSelectedItems();
                int n;
                object[] parts;

                for (n = 0; n < items.Length; n++)
                {
                    parts = DataViewHierarchyAccessor.GetObjectIdentifier(items[n]);
                    if (parts == null) return true;

                    if (parts[2].ToString().StartsWith("SYSTEM_", StringComparison.OrdinalIgnoreCase))
                        return true;
                    if (parts[2].ToString().StartsWith("SYS_", StringComparison.OrdinalIgnoreCase))
                        return true;
                    if (parts[1].ToString().Equals("INFORMATION_SCHEMA", StringComparison.OrdinalIgnoreCase))
                        return true;
                }
                return false;
            }
        }

        private bool SystemIndexSelected
        {
            get
            {
                int[] items = DataViewHierarchyAccessor.GetSelectedItems();
                int n;
                object[] parts;

                for (n = 0; n < items.Length; n++)
                {
                    parts = DataViewHierarchyAccessor.GetObjectIdentifier(items[n]);
                    if (parts == null) return true;                    

                    if (parts.Length > 3)
                    {
                        if (parts[3].ToString().StartsWith("SYSTEM_", StringComparison.OrdinalIgnoreCase))
                            return true;
                        if (parts[3].ToString().StartsWith("SYS_", StringComparison.OrdinalIgnoreCase))
                            return true;
                        if (parts[1].ToString().Equals("INFORMATION_SCHEMA", StringComparison.OrdinalIgnoreCase))
                            return true;
                    }
                }
                return false;
            }
        }

        public override object[] ExecuteCommand(int[] itemIds, OleCommand command, OleCommandExecutionOption executionOption, object arguments)
        {
            return base.ExecuteCommand(itemIds, command, executionOption, arguments);
        }
        /// <summary>
        /// This method executes a specified command, potentially based
        /// on parameters passed in from the data view support XML.
        /// </summary>
        public override object ExecuteCommand(int itemId, OleCommand command, OleCommandExecutionOption executionOption, object arguments)
        {
            object returnValue = null;
            object[] args = arguments as object[];

            if (command.GroupGuid == guidEffiProzCmdSet)
            {
                switch ((cmdid)command.CommandId)
                {
                    case cmdid.Checkpoint:
                        Checkpoint();
                        break;
                    case cmdid.Rekey:
                        ChangePassword(itemId);
                        break;
                    default:
                        returnValue = base.ExecuteCommand(itemId, command, executionOption, arguments);
                        break;
                }
            }
            else if (command.GroupGuid == VSConstants.GUID_VSStandardCommandSet97)
            {
                switch ((VSConstants.VSStd97CmdID)command.CommandId)
                {
                    case VSConstants.VSStd97CmdID.Delete:
                        switch ((string)args[0])
                        {
                            case "Table":
                                DropSelectedTables();
                                break;
                            case "Index":
                                DropSelectedIndexes();
                                break;
                            case "View":
                                DropSelectedViews();
                                break;
                        }
                        break;
                }
            }
            else if (command.GroupGuid == guidDataCmdSet)
            {
                switch ((cmdid)command.CommandId)
                {
                    case cmdid.CreateTable:
                        DesignTable(itemId, null,null);
                        break;
                    case cmdid.CreateView:
                        DesignView(itemId, null,null);
                        break;
                    case cmdid.Alter:
                        switch ((string)args[0])
                        {
                            case "Table":
                                {
                                    object[] parts;
                                    int[] items = DataViewHierarchyAccessor.GetSelectedItems();
                                    parts = DataViewHierarchyAccessor.GetObjectIdentifier(items[0]);
                                    DesignTable(itemId, parts[2].ToString(), parts[1].ToString());
                                }
                                break;
                            case "Index":
                                break;
                            case "View":
                                {
                                    object[] parts;
                                    int[] items = DataViewHierarchyAccessor.GetSelectedItems();
                                    parts = DataViewHierarchyAccessor.GetObjectIdentifier(items[0]);
                                    DesignView(itemId, parts[2].ToString(), parts[1].ToString());
                                }
                                break;
                        }
                        break;
                }
            }
            else
            {
                returnValue = base.ExecuteCommand(itemId, command, executionOption, arguments);
            }
            return returnValue;
        }

        private void DesignTable(int itemId, string tableName, string tableSchema)
        {
            Microsoft.VisualStudio.OLE.Interop.IServiceProvider provider = DataViewHierarchyAccessor.ServiceProvider as Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
            IVsUIShell shell = DataViewHierarchyAccessor.ServiceProvider.GetService(typeof(IVsUIShell)) as IVsUIShell;
            IVsUIHierarchy hier = DataViewHierarchyAccessor.Hierarchy;
            IVsWindowFrame frame;

            if (shell != null)
            {
                TableDesignerDoc form = new TableDesignerDoc(itemId, DataViewHierarchyAccessor, tableName, tableSchema);
                IntPtr formptr = System.Runtime.InteropServices.Marshal.GetIUnknownForObject(form);
                Guid empty = Guid.Empty;
                FakeHierarchy fake = new FakeHierarchy(form, hier);

                int code = shell.CreateDocumentWindow(
                  0, // (uint)(__VSCREATEDOCWIN.CDW_fCreateNewWindow | __VSCREATEDOCWIN.CDW_RDTFLAGS_MASK) | (uint)(_VSRDTFLAGS.RDT_CanBuildFromMemory | _VSRDTFLAGS.RDT_NonCreatable | _VSRDTFLAGS.RDT_VirtualDocument | _VSRDTFLAGS.RDT_DontAddToMRU),
                  form.Name, fake, (uint)itemId, formptr, formptr, ref empty, null, ref guidTableDesignContext, provider, "", form.Caption, null, out frame);

                if (frame != null)
                {
                    object ret;
                    int prop = (int)__VSFPROPID.VSFPROPID_Caption;

                    code = frame.GetProperty(prop, out ret);

                    code = frame.Show();
                }
            }
        }

        private void DesignView(int itemId, string viewName, string viewSchema)
        {
            Microsoft.VisualStudio.OLE.Interop.IServiceProvider provider = DataViewHierarchyAccessor.ServiceProvider as Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
            IVsUIShell shell = DataViewHierarchyAccessor.ServiceProvider.GetService(typeof(IVsUIShell)) as IVsUIShell;
            IVsUIHierarchy hier = DataViewHierarchyAccessor.Hierarchy;
            IVsWindowFrame frame;

            if (shell != null)
            {
                ViewDesignerDoc form = new ViewDesignerDoc(itemId, DataViewHierarchyAccessor, viewName, viewSchema);
                IntPtr formptr = System.Runtime.InteropServices.Marshal.GetIUnknownForObject(form);
                Guid empty = Guid.Empty;
                FakeHierarchy fake = new FakeHierarchy(form, hier);

                int code = shell.CreateDocumentWindow(
                  0, // (uint)(__VSCREATEDOCWIN.CDW_fCreateNewWindow | __VSCREATEDOCWIN.CDW_RDTFLAGS_MASK) | (uint)(_VSRDTFLAGS.RDT_CanBuildFromMemory | _VSRDTFLAGS.RDT_NonCreatable | _VSRDTFLAGS.RDT_VirtualDocument | _VSRDTFLAGS.RDT_DontAddToMRU),
                  form.Name, fake, (uint)itemId, formptr, formptr, ref empty, null, ref guidViewDesignContext, provider, "", form.Caption, null, out frame);

                if (frame != null)
                {
                    object ret;
                    int prop = (int)__VSFPROPID.VSFPROPID_Caption;

                    code = frame.GetProperty(prop, out ret);

                    code = frame.Show();
                }
            }
        }

        private void DropSelectedTables()
        {
            int[] items = DataViewHierarchyAccessor.GetSelectedItems();
            int n;
            object[] parts;

            for (n = 0; n < items.Length; n++)
            {
                parts = DataViewHierarchyAccessor.GetObjectIdentifier(items[n]);
                if (parts == null) continue;

                if (System.Windows.Forms.MessageBox.Show(String.Format(CultureInfo.InvariantCulture, "Drop table {0} ({1}), are you sure?", parts[2], parts[1]), "Confirm delete", System.Windows.Forms.MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
                {
                    string sql = String.Format(CultureInfo.InvariantCulture, "DROP TABLE \"{0}\".\"{1}\"", parts[1], parts[2]);

                    DataViewHierarchyAccessor.Connection.Command.ExecuteWithoutResults(sql, (int)System.Data.CommandType.Text, null, 0);
                    DataViewHierarchyAccessor.DropObjectNode(items[n]);
                }
                else throw new OperationCanceledException();
            }
        }

        private void DropSelectedViews()
        {
            int[] items = DataViewHierarchyAccessor.GetSelectedItems();
            int n;
            object[] parts;

            for (n = 0; n < items.Length; n++)
            {
                parts = DataViewHierarchyAccessor.GetObjectIdentifier(items[n]);
                if (parts == null) continue;

                if (System.Windows.Forms.MessageBox.Show(String.Format(CultureInfo.InvariantCulture, "Drop view {0} ({1}), are you sure?", parts[2], parts[1]), "Confirm delete", System.Windows.Forms.MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
                {
                    string sql = String.Format(CultureInfo.InvariantCulture, "DROP VIEW \"{0}\".\"{1}\"", parts[1], parts[2]);

                    DataViewHierarchyAccessor.Connection.Command.ExecuteWithoutResults(sql, (int)System.Data.CommandType.Text, null, 0);
                    DataViewHierarchyAccessor.DropObjectNode(items[n]);
                }
                else throw new OperationCanceledException();
            }
        }

        private void DropSelectedIndexes()
        {
            int[] items = DataViewHierarchyAccessor.GetSelectedItems();
            int n;
            object[] parts;

            for (n = 0; n < items.Length; n++)
            {
                parts = DataViewHierarchyAccessor.GetObjectIdentifier(items[n]);
                if (parts == null) continue;

                if (System.Windows.Forms.MessageBox.Show(String.Format(CultureInfo.InvariantCulture, "Drop index {0} ({1}), are you sure?", parts[3], parts[1]), "Confirm delete", System.Windows.Forms.MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
                {
                    string sql = String.Format(CultureInfo.InvariantCulture, "DROP INDEX \"{0}\".\"{1}\"", parts[1], parts[3]);

                    DataViewHierarchyAccessor.Connection.Command.ExecuteWithoutResults(sql, (int)System.Data.CommandType.Text, null, 0);
                    DataViewHierarchyAccessor.DropObjectNode(items[n]);
                }
                else throw new OperationCanceledException();
            }
        }

        private void Checkpoint()
        {
            
            DataViewHierarchyAccessor.Connection.Command.ExecuteWithoutResults("CHECKPOINT DEFRAG", (int)System.Data.CommandType.Text, null, 0);
        }

        private void ChangePassword(int itemId)
        {
            DataConnection dataConn = DataViewHierarchyAccessor.Connection;
            DbConnection cnn = DataViewHierarchyAccessor.Connection.ConnectionSupport.ProviderObject as DbConnection;
            if (cnn == null) return;

            EfzConnectionProperties props = new EfzConnectionProperties(cnn.ConnectionString);

            using (ChangePasswordDialog dlg = new ChangePasswordDialog(props))
            {
                if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    if (String.IsNullOrEmpty(dlg.Password))
                        props.Remove("Password");
                    else
                        props["Password"] = dlg.Password;

                    System.Reflection.MethodInfo method = cnn.GetType().GetMethod("ChangePassword", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.InvokeMethod, null, new Type[] { typeof(string) }, null);

                    if (method != null)
                    {
                        method.Invoke(cnn, new object[] { dlg.Password });

                        dataConn.Close();
                        dataConn.DisplayConnectionString = props.ToFullString();
                        dataConn.Open();

                        Refresh(itemId);
                    }
                }
            }
        }

        public void Refresh(int itemId)
        {
            Refresh(DataViewHierarchyAccessor, itemId);
        }

        public static void Refresh(DataViewHierarchyAccessor accessor, int itemId)
        {
            IVsUIHierarchy hier = accessor.Hierarchy as IVsUIHierarchy;
            Guid g = VSConstants.GUID_VSStandardCommandSet97;
            hier.ExecCommand((uint)itemId, ref g, (uint)0xbd, (uint)OleCommandExecutionOption.DoDefault, IntPtr.Zero, IntPtr.Zero);
        }
    }
}